// mem.hpp
// Memory management for ripescript. You should not use any other functions but
// these.
//
// Copyright (C) 2008  Maksim Sipos <msipos@mailc.net>
//
// This file is a part of the Ripe language project.
//
// Ripe is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#ifndef R_MEM_HPP
#define R_MEM_HPP

#include "util/standard.hpp"
#include <cstdlib>
#include <gc/gc.h>
#include <cstring>

// Current implementation only uses the Boehm GC (libgc). Future applications
// will allow the programmer to compile the interpreter using their own, host
// garbage collector.

namespace Ripe {
  // Thrown when memory allocation fails.
  class ErrorAlloc : public Exception {};

  // Prefix mem_*: classical allocation mechanism.

  // Allocates a certain number of bytes on the stack. It is implied that
  // these bytes will be deallocated after the function returns.
  #define mem_alloca(sz) alloca(sz)

  // Frees a memory block. Wrapper around the traditional free().
  static inline void mem_free(void* ptr);

  // Wrapper around the traditional malloc().
  static inline void* mem_malloc(size_t size) throw (ErrorAlloc);

  // Wrapper around the traditional realloc().
  static inline void* mem_realloc(void* ptr, size_t size) throw (ErrorAlloc);

  // Prefix gc_*: garbage collected allocation.

  // Frees a memory block. It may not actually do anything. Should only be used
  // for "large" objects.
  static inline void gc_free(void* ptr);

  // Duplicates a C-style string.
  char* mem_strdup(const char* s) throw(ErrorAlloc);

  // Allocates a certain number of bytes on the heap. These may contain
  // pointers to other blocks. This function is also guaranteed to zero the
  // memory pointed to.
  void* gc_malloc(size_t size) throw(ErrorAlloc);

  // Allocates a number of bytes on the heap. However there should be no
  // pointers to other blocks in this block. Also, this function may not zero
  // the memory block it returns.
  void* gc_malloc_a(size_t size) throw(ErrorAlloc);

  // Acts just like realloc(). It may or may not zero memory, depending on
  // whether gc_malloc() or gc_malloc_a() were called when initially creating
  // the block.
  void* gc_realloc(void* ptr, size_t size) throw(ErrorAlloc);

  // Acts just like strdup().
  char* gc_strdup(char* s) throw(ErrorAlloc);

  // Static inline stuff:
  void mem_free(void* ptr)
  {
    free(ptr);
  }

  void* mem_malloc(size_t size) throw (ErrorAlloc)
  {
    void* p = std::malloc(size);
    if (p == NULL) throw ErrorAlloc();
    return p;
  }

  void* mem_realloc(void* ptr, size_t size) throw (ErrorAlloc)
  {
    void* p = std::realloc(ptr, size);
    if (p == NULL) throw ErrorAlloc();
    return p;
  }

  void gc_free(void* ptr)
  {
    GC_FREE(ptr);
  }
}

// Globally overloaded operators:

// Overloaded new operators that implement regular malloc.
void *operator new(size_t size, int dummy) throw (Ripe::ErrorAlloc);
void *operator new[](size_t size, int dummy) throw (Ripe::ErrorAlloc);

// Overloaded new operators that implement atomic malloc.
void *operator new(size_t size, char dummy) throw (Ripe::ErrorAlloc);
void *operator new[](size_t size, char dummy) throw (Ripe::ErrorAlloc);

// Overloaded delete operators. Use them with above.
void operator delete(void *p, int dummy);
void operator delete[](void *p, int dummy);

// Use this instead of new:
#define rnew     new(0)

// Use this instead of new, when you want atomic alloc:
#define ranew    new('a')

// Use this instead of delete:
#define rdelete  delete(0)

#endif // R_MEM_HPP
